﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using com.kmer.library.Factorys;
using com.kmer;
using com.kmer.Attributes;
using com.kmer.Helper;
using com.kmer.interfaces;

namespace com.kmer.library.com.kmer.Helper {
	/// <summary>
	/// 权限控制
	/// </summary>
	public static class RcHelper {

		#region 数据储存支持
		private static RedisClient _rcClient;
		private const string Prefix = "yh:rc:";
		static RedisClient Client => _rcClient ?? (_rcClient = new RedisClient(5));

		private static string GetKey(string key) {
			return $"{Prefix}{(ConfigurationHelper.Get("isDebug", false) ? "t" : "d")}:{key}";
		}
		#endregion

		#region 权限判断
		/// <summary>
		/// 判断管理员是否有权限（拒绝优先）执行指定的控制器（Controller）
		/// 1、拒绝优先，如果控制器基本上已经拒绝了那么直接返回 false（无权限）
		/// 2、角色优先
		/// </summary>
		/// <param name="StaffNo">用户或者角色</param>
		/// <param name="Controller"></param>
		/// <returns></returns>
		public static bool HasRights(string StaffNo, string Controller) {
			if (string.IsNullOrWhiteSpace(StaffNo)
				|| string.IsNullOrWhiteSpace(Controller))
				return false;
			if (IsDeny(Controller, StaffNo))
				return false;
			return IsAllow(Controller, StaffNo);
		}

		public static IDictionary<string, IList<string>> GetRolesAtAction(string Controller, string Action) {
			var key = $"deny:{Controller}:{Action}";
			var l1 = Client.KeyExists(GetKey($"deny:{Controller}"))
						? Client.GetStringFromSet(GetKey($"deny:{Controller}"), 0, 100)
						: new List<string>();
			var l2 = Client.KeyExists(GetKey($"deny:{Controller}:{Action}"))
						? Client.GetStringFromSet(GetKey($"deny:{Controller}:{Action}"), 0, 100)
						: new List<string>();
			var l3 = Client.KeyExists(GetKey($"allow:{Controller}"))
						? Client.GetStringFromSet(GetKey($"allow:{Controller}"), 0, 100)
						: new List<string>();
			var l4 = Client.KeyExists(GetKey($"allow:{Controller}:{Action}"))
						? Client.GetStringFromSet(GetKey($"allow:{Controller}:{Action}"), 0, 100)
						: new List<string>();
			

			return new Dictionary<string, IList<string>>(){
				{ "deny-controller",l1.ToList()},
				{ "deny-action",l2.ToList()},
				{ "allow-controller", l3.ToList()},
				{ "allow-action", l4.ToList()},
			};
		}

		/// <summary>
		/// 判断管理员是否有权限（拒绝优先）执行指定的控制器（Controller）和动作（Action）
		/// 注意：
		/// 1、拒绝优先，如果控制器基本上已经拒绝了那么直接返回 false（无权限）
		/// 2、角色优先
		/// </summary>
		/// <param name="StaffNo">用户或者角色</param>
		/// <param name="Controller"></param>
		/// <param name="Action"></param>
		/// <returns></returns>
		public static bool HasRights(string StaffNo, string Controller, string Action) {
			if (string.IsNullOrWhiteSpace(StaffNo))
				return false;
			if(!AdminUserFactory.Instance.CheckUser(StaffNo))
				return false;
			if (StaffNo.Length == 5){
				//5位，是用户，获取该用户角色
				var roleList = AdminUserFactory.Instance.GetRoleForUser(StaffNo);
				if (roleList.Any(role => IsDeny(Controller, Action, role))){
					return false;
				}
				if (roleList.Any(role => IsAllow(Controller, Action, role))) {
					return true;
				}
			}
			if (IsDeny(Controller, Action, StaffNo))
				return false;
			return IsAllow(Controller, Action, StaffNo);
		}

		/// <summary>
		/// 是否拒绝
		/// 注意：角色优先
		/// </summary>
		/// <param name="Controller"></param>
		/// <param name="StaffNo"></param>
		/// <returns></returns>
		private static bool IsDeny(string Controller, string StaffNo) {
			var key = $"deny:{Controller}";
			if (!Client.KeyExists(GetKey(key)))
				return false;
			return Client.IsStringSet(GetKey(key), StaffNo);
		}
		/// <summary>
		/// 是否拒绝
		/// 注意：角色优先
		/// </summary>
		/// <param name="Controller"></param>
		/// <param name="Action"></param>
		/// <param name="StaffNo"></param>
		/// <returns></returns>
		private static bool IsDeny(string Controller, string Action, string StaffNo) {
			if (IsDeny(Controller, StaffNo))
				return true;
			var key = $"deny:{Controller}:{Action}";
			if (!Client.KeyExists(GetKey(key)))
				return false;
			return Client.IsStringSet(GetKey(key), StaffNo);
		}
		/// <summary>
		/// 是否允许
		/// 注意：角色优先
		/// </summary>
		/// <param name="Controller"></param>
		/// <param name="StaffNo"></param>
		/// <returns></returns>
		private static bool IsAllow(string Controller, string StaffNo) {
			var key = $"allow:{Controller}";
			if (!Client.KeyExists(GetKey(key)))
				return false;
			return Client.IsStringSet(GetKey(key), StaffNo);
		}
		/// <summary>
		/// 是否允许，控制器有权限默认
		/// 注意：角色优先
		/// </summary>
		/// <param name="Controller"></param>
		/// <param name="Action"></param>
		/// <param name="StaffNo"></param>
		/// <returns></returns>
		private static bool IsAllow(string Controller, string Action, string StaffNo) {
			var key = $"allow:{Controller}:{Action}";
			if (Client.KeyExists(GetKey(key))){
				if (Client.IsStringSet(GetKey(key), StaffNo))
					return true;
			}
			return IsAllow(Controller, StaffNo);
		}
		#endregion

		#region 权限管理
		///// <summary>
		///// 获取用户的所有角色
		///// </summary>
		///// <param name="StaffNo"></param>
		///// <returns></returns>
		//public static IEnumerable<string> GetRoleList(string StaffNo) {
		//	return Client.GetStringFromSet(GetKey($"{StaffNo}:role"), 0, 100);
		//}
		///// <summary>
		///// 添加用户到角色
		///// </summary>
		///// <param name="StaffNo"></param>
		///// <param name="Role"></param>
		//public static void AddRoleToUser(string StaffNo, string Role) {
		//	Client.AddStringToSet(GetKey($"{StaffNo}:role"), Role);
		//}
		///// <summary>
		///// 添加用户到角色
		///// </summary>
		///// <param name="StaffNo"></param>
		///// <param name="Roles"></param>
		//public static void AddRoleToUser(string StaffNo, IEnumerable<string> Roles) {
		//	foreach (var role in Roles) {
		//		Client.AddStringToSet(GetKey($"{StaffNo}:role"), role);
		//	}
		//}
		///// <summary>
		///// 移除用户的角色
		///// </summary>
		///// <param name="StaffNo"></param>
		///// <param name="Role"></param>
		//public static void RemoveRoleFromUser(string StaffNo, string Role) {
		//	Client.RemoveStringFromSet(GetKey($"{StaffNo}:role"), Role);
		//}
		///// <summary>
		///// 移除用户的角色
		///// </summary>
		///// <param name="StaffNo"></param>
		///// <param name="Roles"></param>
		//public static void RemoveRoleFromUser(string StaffNo, IEnumerable<string> Roles) {
		//	foreach (var role in Roles) {
		//		Client.RemoveStringFromSet(GetKey($"{StaffNo}:role"), role);
		//	}
		//}
		///// <summary>
		///// 用户是否拥有某个权限
		///// </summary>
		///// <param name="StaffNo"></param>
		///// <param name="Role"></param>
		///// <returns></returns>
		//public static bool IsUserInRole(string StaffNo, string Role) {
		//	return Client.IsStringSet(GetKey($"{StaffNo}:role"), Role);
		//}
		///// <summary>
		///// 判断用户是否拥有角色（多个或一个）
		///// </summary>
		///// <param name="StaffNo"></param>
		///// <param name="Roles"></param>
		///// <param name="oneOrAll">true的时候 只要拥有一个角色就返回true，否则需要拥有所有的角色才返回ture</param>
		///// <returns></returns>
		//public static bool IsUserInRole(string StaffNo, IEnumerable<string> Roles, bool oneOrAll) {
		//	if (string.IsNullOrWhiteSpace(StaffNo) || !Roles.Any())
		//		return false;
		//	foreach (var role in Roles) {
		//		if (oneOrAll) {
		//			if (Client.IsStringSet(GetKey($"{StaffNo}:role"), role))
		//				return true;
		//		} else {
		//			if (!Client.IsStringSet(GetKey($"{StaffNo}:role"), role))
		//				return false;
		//		}
		//	}
		//	return true;
		//}

		/// <summary>
		/// 拒绝
		/// </summary>
		/// <param name="Target"></param>
		/// <param name="Controller"></param>
		/// <param name="Action"></param>
		public static void DenyIt(string Target, string Controller, string Action) {
			if (Action == "*") {
				Client.AddStringToSet(GetKey($"deny:{Controller}"), Target);
			} else {
				Client.AddStringToSet(GetKey($"deny:{Controller}:{Action}"), Target);
			}
		}
		/// <summary>
		/// 拒绝
		/// </summary>
		/// <param name="Target"></param>
		/// <param name="Controller"></param>
		/// <param name="Action"></param>
		public static void RemoveDeny(string Target, string Controller, string Action) {
			if (Action == "*") {
				Client.RemoveStringFromSet(GetKey($"deny:{Controller}"), Target);
			} else {
				Client.RemoveStringFromSet(GetKey($"deny:{Controller}:{Action}"), Target);
			}
		}
		/// <summary>
		/// 允许
		/// </summary>
		/// <param name="Target"></param>
		/// <param name="Controller"></param>
		/// <param name="Action"></param>
		public static void RemoveAllow(string Target, string Controller, string Action) {
			if (Action == "*") {
				Client.RemoveStringFromSet(GetKey($"allow:{Controller}"), Target);
			} else {
				Client.RemoveStringFromSet(GetKey($"allow:{Controller}:{Action}"), Target);
			}
		}
		/// <summary>
		/// 允许
		/// </summary>
		/// <param name="Target"></param>
		/// <param name="Controller"></param>
		/// <param name="Action"></param>
		public static void AllowIt(string Target, string Controller, string Action) {
			if (Action == "*") {
				Client.AddStringToSet(GetKey($"allow:{Controller}"), Target);
			} else {
				Client.AddStringToSet(GetKey($"allow:{Controller}:{Action}"), Target);
			}
		}

		#endregion

		public static void AddController(ISessionContext apiContext) {
			if (!apiContext.IsBackend)
				return;
			Client.AddStringToSet(GetKey("controller"), new ControllerData{
				Name = apiContext.Controller,
				Description = GetDescription(apiContext.GetType()),
			}.ToJson());
		}
        
		public static IEnumerable<string> GetAllControllers() {
			return Client.GetStringFromSet(GetKey("controller"), 0, 999);
		}
		internal static string GetDescription(Type type) {
			var d = type.GetCustomAttribute<DescriptionAttribute>();
			return d?.Description;
			//var description = (DescriptionAttribute)attribs.FirstOrDefault(item => item is DescriptionAttribute);
		}
        public class ControllerData {
            [ParamDescription("控制器")]
            public string Name { get; set; }

            [ParamDescription("说明")]
            public string Description { get; set; }
        }
	}
}
